package main

import (
	"fmt"
	"io"
	"io/ioutil"
	"os"
	"strings"
	"unsafe"

	"github.com/360EntSecGroup-Skylar/excelize"

	"sync"
	"syscall"

	"github.com/axgle/mahonia"
	"github.com/google/uuid"
	"github.com/lxn/walk"
	. "github.com/lxn/walk/declarative"
	"github.com/panjf2000/ants/v2"

	"net/http"
	"path/filepath"

	//"strings"
	"time"
)

func online(id string, isOnline bool, dtype string, onLineMap *sync.Map) {

	onLineMap.Store(id, State{
		IsOnline: isOnline,
		DType:    dtype,
	})

}

func makeFun(id, ip string, mode string, onLineMap *sync.Map) func() {

	if mode == "http" {
		return func() {
			checkWithHttp(id, "http://"+ip, onLineMap)
		}
	}
	return nil

}

func beginCheck(id, ip string, onLineMap *sync.Map) {
	//fmt.Printf("begin adding running goroutines: %d\n", ants.Running())
	ants.Submit(makeFun(id, ip, "http", onLineMap))
	//fmt.Printf("finish adding running goroutines: %d\n", ants.Running())
	if id == "1122" {
		fmt.Println("****add********1122******")
	}
}

func check(id, ip string) (string, error) {
	timeout := time.Duration(2) * time.Second
	client := http.Client{
		Timeout: timeout,
	}
	resp, err := client.Get(ip)
	if id == "1122" {
		fmt.Println("*http***********1122****end**", err, ip)
	}
	var dtype = "UNKNOWN"
	if resp != nil {
		defer resp.Body.Close()
		body, err := ioutil.ReadAll(resp.Body)
		if err == nil {
			//b := string(body)
			b := mahonia.NewDecoder("gbk").ConvertString(string(body))
			if strings.Contains(b, "WebCam Mon") {
				dtype = "BOX"
			} else {
				dtype = "其他设备"
				//strC := []rune(b)
				begin := strings.Index(b, "<title>")
				if begin >= 0 {

					end := strings.Index(b, "</title>")
					if end >= 0 {
						detail := b[begin+7 : end]
						dtype = dtype + ":" + detail

					}
				}
			}
		}
	}
	return dtype, err

}

func checkWithHttp(id, ip string, onLineMap *sync.Map) {

	if id == "1122" {
		fmt.Println("*http***********1122****begin**")
	}
	var err error
	var dtype string
	for i := 0; i < 20; i++ {
		dtype, err = check(id, ip)
		if err == nil {
			break
		}
	}
	online(id, err == nil, dtype, onLineMap)
	wg.Done()

}

func init() {
	beginPool()
}

func beginPool() {
	ants.NewPool(100)
}

//func main() {
// f, err := excelize.OpenFile("d:/checkfile/exportempty.xlsx")
// if err != nil {
// 	fmt.Println(err)
// 	return
// }

// rows := f.GetRows("Sheet1")
// for i, row := range rows {
// 	if i >= 2 {
// 		if row[3] == nil || row[3] == "" {
// 			f.SetCellValue("Sheet1")
// 		}
// 	}

// }

type MyMainWindow struct {
	*walk.MainWindow
	edit *walk.TextEdit

	path string
}

func main() {
	mw := &MyMainWindow{}
	MW := MainWindow{
		AssignTo: &mw.MainWindow,
		//Icon:     "test.ico",
		Title:   "文件选择对话框",
		MinSize: Size{150, 200},
		Size:    Size{300, 400},
		Layout:  VBox{},
		Children: []Widget{
			TextEdit{
				AssignTo: &mw.edit,
			},
			PushButton{
				Text:      "打开",
				OnClicked: mw.pbClicked,
			},
		},
	}
	if _, err := MW.Run(); err != nil {
		fmt.Fprintln(os.Stderr, err)
		os.Exit(1)
	}

}

type State struct {
	IsOnline bool
	DType    string
}

func (mw *MyMainWindow) pbClicked() {

	dlg := new(walk.FileDialog)
	dlg.FilePath = mw.path

	dlg.Title = "Select File"
	dlg.Filter = "excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*"

	if ok, err := dlg.ShowOpen(mw); err != nil {
		mw.edit.AppendText("Error : File Open\r\n")
		return
	} else if !ok {
		mw.edit.AppendText("Cancel\r\n")
		return
	}
	mw.path = dlg.FilePath
	s := fmt.Sprintf("Select : %s\r\n", mw.path)
	mw.edit.AppendText(s)
	mw.check(mw.path)
}

var wg sync.WaitGroup

func (mw *MyMainWindow) check(fpath string) {
	u1, _ := uuid.NewUUID()

	fdir, fname := filepath.Split(fpath)
	fmt.Println("*************", fpath, fdir, fname)
	//fname := path.Base(fpath)
	filename := fdir + "\\result_" + filepath.Base(fname) + "_" + u1.String() + ".xlsx"
	mw.edit.AppendText(filename + "\r\n")
	sf, _ := os.Open(fpath)
	df, _ := os.Create(filename)
	defer df.Close()
	defer sf.Close()
	io.Copy(df, sf)

	f, err := excelize.OpenFile(filename)
	mw.edit.AppendText("5%\r\n")
	if err != nil {
		fmt.Println("open-----------error---", err)
		mw.edit.AppendText("error\r\n")
		mw.edit.AppendText(err.Error())
		return
	}
	var onlineMap sync.Map
	rows := f.GetRows("Sheet1")
	mapIP := make(map[string]bool)
	for i, row := range rows {
		if i >= 2 {
			errorGrid := fmt.Sprintf("R%d", i+1)
			typeGrid := fmt.Sprintf("%d", i+1)
			if row[3] == "" {

				f.SetCellValue("Sheet1", errorGrid, "ip地址为空")
				continue
			}
			ip := row[3]
			_, ok := mapIP[ip]
			if ok {
				f.SetCellValue("Sheet1", errorGrid, "ip地址重复")
			} else {
				wg.Add(1)
				beginCheck(typeGrid, ip, &onlineMap)
			}

		}
	}

	mw.edit.AppendText("65%\r\n")
	wg.Wait()

	onlineMap.Range(func(k, v interface{}) bool {
		row := k.(string)
		state, ok := v.(State)
		if ok {
			if state.IsOnline {
				f.SetCellValue("Sheet1", "S"+row, "OK")
				f.SetCellValue("Sheet1", "T"+row, state.DType)
			} else {
				f.SetCellValue("Sheet1", "S"+row, "连接失败")
			}

		} else {
			f.SetCellValue("Sheet1", "S"+row, "连接失败")
		}
		return true
	})
	f.Save()
	//mw.edit.AppendText("100%")
	mw.edit.AppendText("100%\r\n")

	shell32 := syscall.NewLazyDLL("shell32.dll")
	ShellExecuteW := shell32.NewProc("ShellExecuteW")
	var hand uintptr = uintptr(0)
	var operator uintptr = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr("open")))
	var fpathw uintptr = uintptr(unsafe.Pointer(syscall.StringToUTF16Ptr(filename)))
	var param uintptr = uintptr(0)
	var dirpath uintptr = uintptr(0)
	var ncmd uintptr = uintptr(1)
	_, _, _ = ShellExecuteW.Call(hand, operator, fpathw, param, dirpath, ncmd)

}
